package controllers

import (
	"bytes"

	// "encoding/base64"
	"encoding/json"
	"fmt"
	"gin/config"
	"gin/models"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tencentyun/cos-go-sdk-v5"
)

type GameController struct{}

type PlayerRpo struct {
	Player models.Players
	User   models.User
}

var (
	bucket = "7072-prod-8gcglsv7211f1cf9-1308485425" // prod-1g1234567
	region = "ap-shanghai"                           // ap-shanghai
)

func (ctrl *GameController) GetGame(c *gin.Context) {
	gameId, _ := strconv.Atoi(c.Param("gameId"))

	var game models.Games

	if config.DB.Where("id = ?", gameId).First(&game).Error != nil { // 查询不到用户
		c.JSON(http.StatusNotFound, gin.H{"error": "Game not found"})
		return
	}

	players := getPlayers(gameId)

	var userIds []uint
	for _, player := range players {
		userIds = append(userIds, player.UserID)
	}

	var users []models.User
	config.DB.Where("id IN ?", userIds).Find(&users)
	userMap := make(map[uint]models.User)
	for _, user := range users {
		userMap[user.ID] = user
	}

	var pList []PlayerRpo
	for _, player := range players {
		var p PlayerRpo
		p.Player = player
		p.User = userMap[player.UserID]
		pList = append(pList, p)
	}

	c.JSON(http.StatusOK, gin.H{
		"game":    game,
		"players": pList,
	})
}

func (ctrl *GameController) CreateGame(c *gin.Context) {
	var game models.Games

	if err := c.ShouldBindJSON(&game); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	config.DB.Create(&game)
	c.JSON(http.StatusOK, game)
}

func (ctrl *GameController) StoreGame(c *gin.Context) {
	gameId := c.Param("gameId")

	var game models.Games

	if config.DB.Where("id = ?", gameId).First(&game).Error != nil { // 查询不到用户
		c.JSON(http.StatusNotFound, gin.H{"error": "Game not found"})
		return
	}

	if game.IsFinished {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Game is already finished"})
		return
	}

	if err := c.ShouldBindJSON(&game); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	config.DB.Save(&game)

	c.JSON(http.StatusOK, game)

}

func (ctrl *GameController) FinishGame(c *gin.Context) {
	gameId, _ := strconv.Atoi(c.Param("gameId"))

	var game models.Games

	if config.DB.Where("id = ?", gameId).First(&game).Error != nil { // 查询不到用户
		c.JSON(http.StatusNotFound, gin.H{"error": "Game not found"})
		return
	}

	if game.IsFinished {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Game is already finished"})
		return
	}

	players := getPlayers(gameId)

	isChampion := true
	var ranking int8 = 1
	for i := range players {
		if isChampion {
			players[i].IsChampion = isChampion
			isChampion = false
		}
		players[i].Ranking = ranking
		ranking++
	}

	game.IsFinished = true

	config.DB.Save(&players)
	config.DB.Save(&game)

	c.JSON(http.StatusOK, gin.H{
		"game":    game,
		"players": players,
	})
}

func (ctrl *GameController) GameList(ctx *gin.Context) {
	openID := ctx.GetHeader("X-WX-OPENID")
	var user models.User
	if openID == "" { // 检查是否包含openID
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code":   0,
			"msg":    "openID不能为空",
			"openID": openID,
		})
		return
	}

	page, _ := strconv.Atoi(ctx.Param("page"))
	pageSize := 20

	offset := (page - 1) * pageSize

	if config.DB.Where("wx_uid = ?", openID).First(&user).Error != nil { // 查询用户
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code":   0,
			"msg":    "用户不存在",
			"openID": openID,
		})
		return
	}

	var games []models.Games
	config.DB.Where("create_user_id = ?", user.ID).Order("created_at DESC").Limit(pageSize).Offset(offset).Find(&games)

	ctx.JSON(http.StatusOK, games)
}

func (ctrl *GameController) ShareGame(ctx *gin.Context) {

	gameId, _ := strconv.Atoi(ctx.Param("gameId"))

	var game models.Games
	if config.DB.Where("id = ?", gameId).First(&game).Error != nil { // 查询不到用户
		ctx.JSON(http.StatusNotFound, gin.H{"error": "Game not found"})
		return
	}

	if game.PicUrl != "" {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "Success",
			"data":    game.PicUrl,
		})
		return
	}

	// 准备请求参数
	requestParams := map[string]any{
		"page":  "pages/game/game",
		"scene": "id=" + strconv.Itoa(gameId),
		"width": 430,
	}

	// 将请求参数序列化为 JSON
	requestBody, err := json.Marshal(requestParams)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal request body"})
		return
	}

	url := "http://api.weixin.qq.com/wxa/getwxacodeunlimit"
	resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to make POST request"})
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusOK {
		data, err := io.ReadAll(resp.Body)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read response body"})
			return
		}

		if bytes.HasPrefix(data, []byte("{")) {
			var wxErr struct {
				ErrCode int    `json:"errcode"`
				ErrMsg  string `json:"errmsg"`
			}
			if err := json.Unmarshal(data, &wxErr); err == nil {
				ctx.JSON(http.StatusInternalServerError, gin.H{
					"error": fmt.Errorf("wechat API error %d: %s", wxErr.ErrCode, wxErr.ErrMsg).Error(),
				})
				return
			}
		}

		uploadWxaCode(data, ctx, "")
	} else {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"error": "Failed to get WxaCode",
			"data":  resp.Body,
			"code":  resp.StatusCode,
		})
	}
}

func newCOSClient(c *gin.Context) *cos.Client {
	authInfo, err := getTempAuthFromWX()
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"message": "Success",
			"auth":    authInfo,
			"err":     err.Error(),
		})
		return nil
	}

	urlStr := fmt.Sprintf("https://%s.cos.%s.myqcloud.com", bucket, region)
	u, _ := url.Parse(urlStr)
	b := &cos.BaseURL{BucketURL: u}

	client := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			// 如果使用临时密钥需要填入，临时密钥生成和使用指引参见 https://cloud.tencent.com/document/product/436/14048
			SecretID:     authInfo.TmpSecretID,
			SecretKey:    authInfo.TmpSecretKey,
			SessionToken: authInfo.Token,
		},
	})

	if client == nil {
		fmt.Printf("init client Failed!")
	}

	return client
}

func uploadWxaCode(data []byte, c *gin.Context, objectKey string) {
	cli := newCOSClient(c)
	if objectKey == "" {
		objectKey = fmt.Sprintf("wxcode/%d.png", time.Now().Unix())
	}

	// 上传
	var err error
	opt := &cos.ObjectPutOptions{
		ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
			ContentType: "image/png", // 小程序码实际是png格式
		},
	}
	_, err = cli.Object.Put(c, objectKey, bytes.NewReader(data), opt)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
		return
	}

	// 公开读地址（根路径+objectKey）
	// publicURL := fmt.Sprintf("https://%s.cos.%s.myqcloud.com/%s", bucket, region, objectKey)
	publicURL := fmt.Sprintf("https://%s.tcb.qcloud.la/%s", bucket, objectKey)

	c.JSON(http.StatusOK, gin.H{
		"message": "Success",
		"data":    publicURL,
	})
}

func getPlayers(gameId int) []models.Players {
	var players []models.Players
	config.DB.Where("game_id = ?", gameId).Order("score DESC").Find(&players)
	return players
}
